package it.unipd.fbaron.mind_reader_squared.activities;

import it.unipd.fbaron.mind_reader_squared.R;
import it.unipd.fbaron.mind_reader_squared.model.SymbolDAO;
import it.unipd.fbaron.mind_reader_squared.model.SymbolLogic;

import java.util.ArrayList;

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabContentFactory;
import android.widget.TextView;

public class TabsFragment extends Fragment {

	private TabHost tabHost;
	private SymbolListManager symbolListManagerM1;
	private SymbolListManager symbolListManagerM2;
	private SymbolListManager currSymbolListManager;
	private int precTab;
	private int currTab;
	private TextView sideText;

	private OnTabEventListener listener;

	/*
	 * Callback interface to communicate with ManageSymbol activity
	 */
	public interface OnTabEventListener {
		public void onChangeTab(int newTabIndex, int oldTabIndex);

		public void onSymbolSelected(int index, int tabIndex);
		
		public void onBackSelected(int parent_id);
	}

	/*
	 * To ensure that the host activity implements this interface, fragment A's
	 * onAttach() callback method (which the system calls when adding the
	 * fragment to the activity) instantiates an instance of
	 * OnArticleSelectedListener by casting the Activity that is passed into
	 * onAttach()
	 */
	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		try {
			listener = (OnTabEventListener) activity;
		} catch (ClassCastException e) {
			throw new ClassCastException(activity.toString()
					+ " must implement OnOptionsEventListener");
		}
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		// Inflate the layout for this fragment
		View v = inflater.inflate(R.layout.tab_fragment_layout, container,
				false);

		tabHost = (TabHost) v.findViewById(android.R.id.tabhost);
		tabHost.setup();

		// Create tabs
		tabHost.addTab(tabHost.newTabSpec(getString(R.string.m1))
				.setIndicator(getString(R.string.m1))
				.setContent(new ListContentFactory()));
		tabHost.addTab(tabHost.newTabSpec(getString(R.string.m2))
				.setIndicator(getString(R.string.m2))
				.setContent(new ListContentFactory()));
		tabHost.addTab(tabHost.newTabSpec(getString(R.string.new_symbol))
				.setIndicator(getString(R.string.new_symbol))
				.setContent(new AddContentFactory()));

		currTab = 0;

		tabHost.setOnTabChangedListener(new OnTabChangeListener() {
			@Override
			public void onTabChanged(String tabId) {
				precTab = currTab;
				currTab = tabHost.getCurrentTab();
				if (currTab == 0) {
					currSymbolListManager = symbolListManagerM1;
					currSymbolListManager
							.setSymbolList(SymbolLogic
									.getInstance(
											((ManageSymbolActivity) getActivity()).dbHelper)
									.getM1SymbolList(
											((ManageSymbolActivity) getActivity())
													.getProfileId()));
				}
				if (currTab == 1) {
					currSymbolListManager = symbolListManagerM2;
					currSymbolListManager.resetPath();
					currSymbolListManager.setParent(0);
					currSymbolListManager
							.setSymbolList(SymbolLogic
									.getInstance(
											((ManageSymbolActivity) getActivity()).dbHelper)
									.getM2SymbolList(
											((ManageSymbolActivity) getActivity())
													.getProfileId(), 0));
				}
				if (currTab == 2) {
					currSymbolListManager = null;
				}
				listener.onChangeTab(currTab, precTab);
			}
		});

		return v;
	}

	private class ListContentFactory implements TabContentFactory {
		/*
		 * Factory that generate content for tabs as lists
		 */

		@Override
		public View createTabContent(String tag) {
			View list;
			// Setting adapter to the list
			if (tabHost.getCurrentTab() == 0) {
				symbolListManagerM1 = new SymbolListManager(
						getActivity(),
						SymbolLogic.getInstance(((ManageSymbolActivity) getActivity()).dbHelper).getM1SymbolList(((ManageSymbolActivity) getActivity()).getProfileId()), 
						true);
				currSymbolListManager = symbolListManagerM1;
				list = symbolListManagerM1.getListView();
			} else {
				symbolListManagerM2 = new SymbolListManager(
						getActivity(),
						SymbolLogic
								.getInstance(
										((ManageSymbolActivity) getActivity()).dbHelper)
								.getM2SymbolList(
										((ManageSymbolActivity) getActivity())
												.getProfileId(), 0), false);
				list = symbolListManagerM2.getListView();
			}

			return list;
		}

	}

	/*
	 * A private class that manages all the logic of the symbols list. The view
	 * associated to a SymbolListManager could be obtained with getListView().
	 */
	private class SymbolListManager {

		private boolean symbolMode; // true => M1, false => M2
		private ArrayAdapter<SymbolDAO> adapter;
		private ArrayList<SymbolDAO> lastSavedSymbolList;
		private View view;
		private TextView path;
		private ImageButton back;
		private int parent;
		
		private static final String SEPARATOR = " > "; 

		public SymbolListManager(Context context,
				ArrayList<SymbolDAO> symbol_list, boolean symbol_mode) {
			
			this.symbolMode = symbol_mode;
			
			//Use multilevel adapter if mode 2 is selected
			if (symbolMode == true) {
				this.adapter = new ArrayAdapter<SymbolDAO>(context, R.layout.list_item,
						R.id.list_item_text, symbol_list);
			}
			else {
				this.adapter = new ArrayAdapterPlus(context, R.layout.list_item, symbol_list);
			}
			
			saveChanges(null);

			// Create View
			ListView list_view = new ListView(context);
			list_view.setAdapter(adapter);
			// Setting listener of the list
			list_view.setOnItemClickListener(new OnItemClickListener() {

				@Override
				public void onItemClick(AdapterView<?> arg0, View arg1,
						int arg2, long arg3) {
					
					listener.onSymbolSelected(arg2, tabHost.getCurrentTab());
					
					if (!symbolMode) {
						//Get lower level symbols list
						ArrayList<SymbolDAO> new_list = SymbolLogic.getInstance(
									((ManageSymbolActivity) getActivity()).dbHelper)
							.getM2SymbolList(
									((ManageSymbolActivity) getActivity()).getProfileId(), adapter.getItem(arg2).getId());
						
						if (new_list != null && new_list.size() > 0) {
							//update path
							addToPath(adapter.getItem(arg2).getText());
							back.setAlpha(200);
							back.setClickable(true);
							
							//update list
							setParent(adapter.getItem(arg2).getId());
							setSymbolList(new_list);
						}
					}
				}
			});
			
			//Print only the list if Mod1. In mod 2 print also the path of selected symbol.
			if (symbolMode == true) {
				view = list_view;
			}
			else {
				path = new TextView(context);
				path.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT,8));
				
				path.setGravity(Gravity.LEFT);
				path.setBackgroundResource(R.drawable.other_info_frame_default2);
				resetPath();
				setParent(0);
				
				back = new ImageButton(context);
				back.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT,2));
				back.setImageResource(R.drawable.options_left);
				if (parent == 0) {
					back.setAlpha(30);
					back.setClickable(false);
				}
				
				//Setting listener of back button
				back.setOnClickListener(new OnClickListener() {
					
					@Override
					public void onClick(View v) {
						if (!adapter.isEmpty()) {
							SymbolDAO parent_symbol = SymbolLogic.getInstance(
									((ManageSymbolActivity) getActivity()).dbHelper)
									.getSymbolById(parent);
							SymbolDAO parent_parent_symbol = null;
							if (parent_symbol.getParent() > 0) {
								parent_parent_symbol = SymbolLogic.getInstance(
										((ManageSymbolActivity) getActivity()).dbHelper)
										.getSymbolById(parent_symbol.getParent());
							}
							
							//Update path
							String new_parent_from_path = backInPath();
							
							//Update list
							if (parent_parent_symbol != null && new_parent_from_path.equals(parent_parent_symbol.getText())) {
								//Get higher level symbols list
								ArrayList<SymbolDAO> new_list = SymbolLogic.getInstance(
											((ManageSymbolActivity) getActivity()).dbHelper)
									.getM2SymbolList(
											((ManageSymbolActivity) getActivity()).getProfileId(), parent_symbol.getParent());
								setParent(parent_symbol.getParent());
								setSymbolList(new_list);
							}
							else {
								//path it's no more valid, reset list to level 0
								ArrayList<SymbolDAO> new_list = SymbolLogic.getInstance(
											((ManageSymbolActivity) getActivity()).dbHelper)
									.getM2SymbolList(
											((ManageSymbolActivity) getActivity()).getProfileId(), 0);
								setParent(0);
								setSymbolList(new_list);
								//re-update path
								path.setText(SEPARATOR);
							}
							
							listener.onBackSelected(parent);
						}
					}
				});
				
				LinearLayout h_layout = new LinearLayout(context);
				h_layout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
				h_layout.setWeightSum(10);
				h_layout.setOrientation(LinearLayout.HORIZONTAL);
				h_layout.setGravity(Gravity.CENTER_VERTICAL);
				h_layout.addView(path);
				h_layout.addView(back);
				
				LinearLayout v_layout = new LinearLayout(context);
				v_layout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
				v_layout.setOrientation(LinearLayout.VERTICAL);
				v_layout.addView(h_layout);
				v_layout.addView(list_view);
				view = v_layout;
			}
		}

		public View getListView() {
			return view;
		}

		public void saveChanges(SymbolDAO symbol) {
			if (lastSavedSymbolList == null) {
				lastSavedSymbolList = new ArrayList<SymbolDAO>();
			}
			lastSavedSymbolList.clear();

			int index = -1;
			if (symbol != null)
				index = findIndexFromId(symbol.getId());
			if (index >= 0) {
				adapter.remove(adapter.getItem(index));
				adapter.insert(symbol, index);
			}
			for (int i = 0; i < adapter.getCount(); i++) {
				lastSavedSymbolList.add(i, new SymbolDAO(adapter.getItem(i)));
			}
		}

		public ArrayList<SymbolDAO> getSymbolList() {
			ArrayList<SymbolDAO> tmp = new ArrayList<SymbolDAO>();
			for (int i = 0; i < adapter.getCount(); i++) {
				tmp.add(i, adapter.getItem(i));
			}
			return tmp;
		}

		public void setSymbolList(ArrayList<SymbolDAO> symbol_list) {
			adapter.clear();
			for (int i = 0; i < symbol_list.size(); i++)
				adapter.add(symbol_list.get(i));
			saveChanges(null);
			notifyViewChanges();
			
			if (currTab == 1 && parent == 0) {
				back.setAlpha(30);
				back.setClickable(false);
			}
		}

		public void removeFromList(final int symbol_id, boolean save) {
			int index = findIndexFromId(symbol_id);
			adapter.remove(adapter.getItem(index));
			if (symbolMode == true) {
				for (int i = index; i < adapter.getCount(); i++) {
					adapter.getItem(i).setM1Pos(i);
				}
			}
			else {
				for (int i = index; i < adapter.getCount(); i++) {
					adapter.getItem(i).setM2Pos(i);
				}
				if (adapter.getCount() == 0) {
					changeTab(0);
					changeTab(1);
				}
			}
			if (save)
				saveChanges(null);
			notifyViewChanges();
		}
		
		public void appendToList(final int symbol_id) {
			int index = -1;
			for (int i=0; i<lastSavedSymbolList.size(); i++) {
				if (lastSavedSymbolList.get(i).getId() == symbol_id)
					index = i;
			}
			if (index >= 0) {
				SymbolDAO s = new SymbolDAO(lastSavedSymbolList.get(index));
				s.setM2Pos(adapter.getCount());
				adapter.add(s);
			}
			notifyViewChanges();
		}

		public int moveUpInList(final int symbol_id) {
			SymbolDAO switchUp;
			SymbolDAO switchDown;

			int index = findIndexFromId(symbol_id);
			if (index > 0) {
				switchUp = adapter.getItem(index);
				switchDown = adapter.getItem(index - 1);

				adapter.remove(switchDown);
				adapter.remove(switchUp);

				// switch pos
				int tmp;
				tmp = getPos(switchDown);
				setPos(switchDown, getPos(switchUp));
				setPos(switchUp, tmp);

				adapter.insert(switchDown, index - 1);
				adapter.insert(switchUp, index - 1);

				notifyViewChanges();
				return index - 1;
			}
			return -1;
		}

		public int moveDownInList(final int symbol_id) {
			SymbolDAO switchUp;
			SymbolDAO switchDown;

			int index = findIndexFromId(symbol_id);
			if (index + 1 < adapter.getCount()) {
				switchUp = adapter.getItem(index + 1);
				switchDown = adapter.getItem(index);

				adapter.remove(switchDown);
				adapter.remove(switchUp);

				// switch pos
				int tmp;
				tmp = getPos(switchDown);
				setPos(switchDown, getPos(switchUp));
				setPos(switchUp, tmp);

				adapter.insert(switchDown, index);
				adapter.insert(switchUp, index);

				notifyViewChanges();
				return index + 1;
			}
			return -1;
		}

		public void discardChanges() {
			adapter.clear();
			for (int i = 0; i < lastSavedSymbolList.size(); i++) {
				adapter.insert(new SymbolDAO(lastSavedSymbolList.get(i)), i);
			}
			notifyViewChanges();
		}

		public ArrayList<SymbolDAO> getLastSavedSymbolList() {
			return lastSavedSymbolList;
		}

		private int findIndexFromId(int symbol_id) {
			int index = -1;
			for (int i = 0; i < adapter.getCount() && index < 0; i++) {
				if (adapter.getItem(i).getId() == symbol_id) {
					index = i;
				}
			}
			return index;
		}

		private void notifyViewChanges() {
			adapter.notifyDataSetChanged();
		}

		private int getPos(SymbolDAO symbol) {
			if (symbolMode) {
				return symbol.getM1Pos();
			} else {
				return symbol.getM2Pos();
			}
		}

		private void setPos(SymbolDAO symbol, int pos) {
			if (symbolMode) {
				symbol.setM1Pos(pos);
			} else {
				symbol.setM2Pos(pos);
			}
		}
		
		private void addToPath(String symbol_text) {
			String text = "";
			if (!path.getText().toString().equals(SEPARATOR))
				text += path.getText().toString();
			path.setText(text + SEPARATOR + symbol_text);
		}
		
		/*
		 * Delete last symbol from the path, show new path in TextView and return the name/text of new parent
		 */
		private String backInPath() {
			String text = path.getText().toString();
			if (text.equals(SEPARATOR))
				return "";
			int end_pos = text.lastIndexOf(SEPARATOR);
			text = text.subSequence(0, end_pos).toString();
			if (text.equals(""))
				text = SEPARATOR;
			path.setText(text);
			
			end_pos = text.lastIndexOf(SEPARATOR);
			text = text.subSequence(end_pos+SEPARATOR.length(), text.length()).toString();
			return text;
		}
		
		private void resetPath() {
			path.setText(SEPARATOR);
		}
		
		public int getParent() {
			return this.parent;
		}
		
		public void setParent(int parent) {
			this.parent = parent;
		}
		
		//Adapter for the multilevel list of Mod 2
		private class ArrayAdapterPlus extends ArrayAdapter<SymbolDAO> {

	        private ArrayList<SymbolDAO> symbol_list;

	        public ArrayAdapterPlus(Context context, int textViewResourceId, ArrayList<SymbolDAO> symbol_list) {
	                super(context, textViewResourceId, symbol_list);
	                this.symbol_list = symbol_list;
	        }

	        @Override
	        public View getView(int position, View convertView, ViewGroup parent) {
	                View v = convertView;
	                if (v == null) {
	                    LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	                    v = vi.inflate(R.layout.list_item, null);
	                }
	                SymbolDAO symbol = symbol_list.get(position);
	                TextView plus = (TextView) v.findViewById(R.id.list_item_plus);
                    plus.setText("    ");
                    plus.setPadding(10,10,10,10);
	                if (SymbolLogic.getInstance(((ManageSymbolActivity) getActivity()).dbHelper).getSymbolNumChildren(symbol.getId()) > 0) {
	                        plus.setText("[+]");
	                }
                    TextView text = (TextView) v.findViewById(R.id.list_item_text);
                    text.setText(symbol.getText());
	                return v;
	        }
		}
		
	}

	private class AddContentFactory implements TabContentFactory {
		/*
		 * Factory that generate content for tabs as single text
		 */
		@Override
		public View createTabContent(String tag) {
			Context context = getActivity();

			TextView textView = new TextView(context);
			textView.setText(getString(R.string.new_symbol_desc));
			textView.setGravity(Gravity.CENTER_HORIZONTAL
					| Gravity.CENTER_VERTICAL);
			textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30);
			textView.setLayoutParams(new LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
			textView.setPadding(50, 0, 50, 0);
			sideText = textView;
			return sideText;
		}
	}

	protected ArrayList<SymbolDAO> getSymbolList() {
		if (currSymbolListManager != null)
			return currSymbolListManager.getSymbolList();
		else
			return new ArrayList<SymbolDAO>();
	}
	
	protected void setSymbolList(ArrayList<SymbolDAO> symbol_list) {
		currSymbolListManager.setSymbolList(symbol_list);
	}

	public void removeFromList(int symbol_id, boolean save) {
		currSymbolListManager.removeFromList(symbol_id, save);
	}
	
	public void appendToList(int symbol_id) {
		currSymbolListManager.appendToList(symbol_id);
	}

	public int moveUpInList(int symbol_id) {
		return currSymbolListManager.moveUpInList(symbol_id);
	}

	public int moveDownInList(int symbol_id) {
		return currSymbolListManager.moveDownInList(symbol_id);
	}

	public void discardChanges() {
		if (currSymbolListManager != null)
			currSymbolListManager.discardChanges();
	}

	public void saveChanges(SymbolDAO symbol) {
		if (currSymbolListManager != null)
			currSymbolListManager.saveChanges(symbol);
	}

	public ArrayList<SymbolDAO> getLastSavedSymbolList() {
		return currSymbolListManager.getLastSavedSymbolList();
	}

	public void changeTab(int tabIndex) {
		tabHost.setCurrentTab(tabIndex);
	}

	public int getTabIndex() {
		return tabHost.getCurrentTab();
	}

	public void setSideText(String text) {
		sideText.setText(text);
	}

	public int getListParent() {
		if (currTab == 1)
			return currSymbolListManager.getParent();
		else
			return 0;
	}
}
